/** * Copyright (C) 2001-2017 by RapidMiner and the contributors * * Complete list of developers available at our web site: * * http://rapidminer.com * * This program is free software: you can redistribute it and/or modify it under the terms of the * GNU Affero General Public License as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License along with this program. * If not, see http://www.gnu.org/licenses/. */ package com.rapidminer.tools.config.gui; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.GridLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.logging.Level; import javax.swing.AbstractButton; import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.DefaultListModel; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JLayer; import javax.swing.JList; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.KeyStroke; import javax.swing.ListSelectionModel; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.xml.ws.WebServiceException; import org.jdesktop.swingx.JXTaskPane; import org.jdesktop.swingx.JXTaskPaneContainer; import org.jdesktop.swingx.painter.MattePainter; import com.rapidminer.Process; import com.rapidminer.gui.ApplicationFrame; import com.rapidminer.gui.RapidMinerGUI; import com.rapidminer.gui.tools.ExtendedJScrollPane; import com.rapidminer.gui.tools.ProgressThread; import com.rapidminer.gui.tools.ResourceAction; import com.rapidminer.gui.tools.ResourceActionAdapter; import com.rapidminer.gui.tools.ScrollableJPopupMenu; import com.rapidminer.gui.tools.SwingTools; import com.rapidminer.gui.tools.UpdateQueue; import com.rapidminer.gui.tools.components.TransparentGlassPanePanel; import com.rapidminer.gui.tools.dialogs.ButtonDialog; import com.rapidminer.parameter.Parameters; import com.rapidminer.repository.Repository; import com.rapidminer.repository.RepositoryException; import com.rapidminer.repository.RepositoryManager; import com.rapidminer.repository.internal.remote.RemoteRepository; import com.rapidminer.tools.I18N; import com.rapidminer.tools.LogService; import com.rapidminer.tools.config.AbstractConfigurable; import com.rapidminer.tools.config.Configurable; import com.rapidminer.tools.config.ConfigurationManager; import com.rapidminer.tools.config.actions.ActionResult; import com.rapidminer.tools.config.actions.ActionResult.Result; import com.rapidminer.tools.config.actions.ConfigurableAction; import com.rapidminer.tools.config.gui.event.ConfigurableEvent; import com.rapidminer.tools.config.gui.event.ConfigurableModelEventListener; import com.rapidminer.tools.config.gui.model.ConfigurableModel; import com.rapidminer.tools.config.gui.renderer.ConfigurableInfoLabelRenderer; import com.rapidminer.tools.config.gui.renderer.ConfigurableInfoLabelRenderer.ConfigurableInfoLabelType; import com.rapidminer.tools.config.gui.renderer.ConfigurableRenderer; /** * Dialog which can be used to manage all {@link Configurable}s in RapidMiner Studio. * * @author Marco Boeck, Sabrina Kirstein * */ public class ConfigurableDialog extends ButtonDialog { private static final long serialVersionUID = 725095214927473103L; /** icon displayed in case of configurator success */ private static final ImageIcon SUCCESS_ICON = SwingTools.createIcon("24/check.png"); /** icon displayed in case of configurator action failure */ private static final ImageIcon FAILURE_ICON = SwingTools.createIcon("24/error.png"); /** icon displayed in case of running action */ private static final ImageIcon WORKING_ICON = SwingTools.createIcon("24/hourglass.png"); /** icon displayed in case of storing configurables */ private static final ImageIcon WAITING_ICON = SwingTools.createIcon("48/rm_logo_loading.gif"); /** size of the list of configurables */ private static final Dimension CONFIG_LIST_SIZE = new Dimension(300, 500); /** the dimension for the spacer in the middle */ private static final Dimension DIMENSION_SPACER_MIDDLE = new Dimension(10, 100); /** the dimension for the spacer on the right side of the params */ private static final Dimension DIMENSION_SPACER_PARAMS = new Dimension(5, 100); /** the background color of the JLists with Configurables */ private static final Color LIGHTER_GRAY = new Color(250, 250, 250); /** the background color of the name panel showing the header of a Configurable */ private static final Color NAME_PANEL_GRAY = new Color(220, 220, 220); /** separator if the title has to be cut */ public static final String SEPARATOR = "[...]"; /** the model backing the info label list for connections */ private DefaultListModel<String> localInfoLabelListModel; /** the model backing the configurable list for local connections */ private DefaultListModel<Configurable> localConfigListModel; /** the model backing the info label list for server connections */ private Map<String, DefaultListModel<String>> remoteInfoLabelListModels; /** the model backing the configurable list for server connections */ private Map<String, DefaultListModel<Configurable>> remoteConfigListModels; /** the {@link JList} containing the local info labels */ private JList<String> localInfoLabelList; /** the {@link JList} containing the local {@link Configurable}s */ private JList<Configurable> localConfigList; /** the {@link JList} containing the remote info labels */ private Map<String, JList<String>> remoteInfoLabelLists; /** the {@link JList} containing the remote {@link Configurable}s */ private Map<String, JList<Configurable>> remoteConfigLists; /** the controller for the local connections in this view */ private ConfigurableController localController; /** the controller for the remote connections in this view */ private Map<String, ConfigurableController> remoteControllers; /** the listener on the localModel */ private ConfigurableModelEventListener localListener; /** the listeners on the remote models */ private Map<String, ConfigurableModelEventListener> remoteListener; /** the local configuration pane */ private JXTaskPane localTaskPane; /** the remote configurations pane */ private Map<String, JXTaskPane> remoteTaskPanes; /** the panel which holds the parameter GUI for the selected {@link Configurable} */ private JPanel parameterPanel; /** the text saying that n users have access to the configurable */ private String userAccessText = I18N.getGUILabel("configurable_dialog.source_access"); /** the text saying that a single user has access to the configurable */ private String singleUserAccessText = I18N.getGUILabel("configurable_dialog.source_access_single_user"); /** the label displaying the user groups that have access to a remote connection */ private JLabel userAccessLabel; /** the button which can be clicked to change the user group access to a remote connection */ private JButton userAccessButton; /** the label displaying the test action results */ private JLabel testLabel; /** the panel containing the test action, test button */ private final JPanel actionPanel = new JPanel(new GridBagLayout()); /** the button which can be clicked to perform the test action for a configurable */ private JButton testButton; /** the outer panel of the parameters part */ private JPanel outerPanel; /** the outer panel of the dialog */ private JPanel realOuterPanel; /** the button to save all configurables */ private JButton okButton; /** the button to cancel the dialog */ private JButton cancelButton; /** * the panel which holds the name of a configurable, the button to change it and a button to * delete the configurable */ private JPanel namePanel; /** the label displaying the name of a configurable */ private JLabel nameLabel; /** the button which displays the configurator actions for a configurable */ private JButton configActionsButton; /** the current panel showing the parameters for the selected configurable */ private ConfiguratorParameterPanel configParamPanel; /** the {@link Configurable} which is selected (or was selected while switching) */ private Configurable previousConfigurable; /** the {@link JXTaskPaneContainer} containing the {@link Configurable}s */ private JXTaskPaneContainer configContainer; /** the button to rename a Configurable */ private JButton renameButton; /** the button to remove a Configurable */ private JButton removeButton; /** the location of the opened process, null (local) or remote repository */ private RemoteRepository processLocation; /** preferred type id for new configurables (needed for start out of the parameter view) */ private String preferredTypeId; private Map<String, Boolean> configurablesFetching = new HashMap<>(); private Map<String, Boolean> addingConfigurablesFirstTime = new HashMap<>(); protected static boolean isAddingDialogOpened = false; private final ConfigurableModelEventListener modelEventListener = new ConfigurableModelEventListener() { @Override public void modelChanged(ConfigurableEvent e) { int index = 0; switch (e.getEventType()) { case CONFIGURABLES_CHANGED: // clear all models localConfigListModel.clear(); for (DefaultListModel<Configurable> remoteConfigListModel : remoteConfigListModels.values()) { remoteConfigListModel.clear(); } // fill list model with existing Configurables for (Configurable config : localController.getModel().getConfigurables()) { localConfigListModel.addElement(config); } for (String key : remoteConfigListModels.keySet()) { for (Configurable config : getRemoteConfigurables(key)) { remoteConfigListModels.get(key).addElement(config); } } break; case CONFIGURABLE_ADDED: // find the correct list if (e.getConfigurable().getSource() == null) { if (localController.getModel().getConfigurables().size() == 1) { localInfoLabelListModel.removeAllElements(); } index = localController.getModel().getConfigurables().indexOf(e.getConfigurable()); localConfigListModel.add(index, e.getConfigurable()); localConfigList.setSelectedIndex(index); unselectAllOtherLists(null); } else { String source = e.getConfigurable().getSource().getName(); boolean notYetManuallyConnected = addingConfigurablesFirstTime.get(source) == null || !addingConfigurablesFirstTime.get(source).booleanValue(); boolean notYetAutoConnected = remoteControllers.get(source).getModel().wasVersionCheckDone(); lastSelected = e.getConfigurable(); if (notYetManuallyConnected && notYetAutoConnected) { if (remoteControllers.get(source).getModel().getConfigurables().size() == 1) { remoteInfoLabelListModels.get(source).removeAllElements(); } index = getRemoteConfigurables(source).indexOf(e.getConfigurable()); remoteConfigListModels.get(source).add(index, e.getConfigurable()); remoteConfigLists.get(source).setSelectedIndex(index); unselectAllOtherLists(e.getConfigurable().getSource()); } } break; case CONFIGURABLE_REMOVED: // find the correct list if (e.getConfigurable().getSource() == null) { index = localConfigList.getSelectedIndex(); localConfigListModel.removeElement(e.getConfigurable()); if (localConfigListModel.size() > 0) { // select the next entry (or none if it was the last) index = Math.min(index, localConfigListModel.size() - 1); } else { localInfoLabelListModel.removeAllElements(); localInfoLabelListModel.addElement(ConfigurableInfoLabelType.NO_CONNECTIONS.toString()); localTaskPane.repaint(); } localConfigList.setSelectedIndex(index); } else { String source = e.getConfigurable().getSource().getName(); if (!remoteConfigListModels.containsKey(source)) { // nothing to be removed break; } index = remoteConfigLists.get(source).getSelectedIndex(); remoteConfigListModels.get(source).removeElement(e.getConfigurable()); if (remoteConfigListModels.get(source).size() > 0) { // select the next entry (or none if it was the last) index = Math.min(index, remoteConfigListModels.get(source).size() - 1); } else { // if there are no connections available remoteInfoLabelListModels.get(source).removeAllElements(); remoteInfoLabelListModels.get(source) .addElement(ConfigurableInfoLabelType.NO_CONNECTIONS.toString()); remoteTaskPanes.get(source).repaint(); } remoteConfigLists.get(source).setSelectedIndex(index); } break; case LOADED_FROM_REPOSITORY: // new remote connections are loaded and displayed in one block instead // of flying in separately Configurable c = e.getConfigurable(); if (c != null) { if (c.getSource() != null) { // check if the refresh button should be visible updateRefreshButton(); updateSmallLoginButton(); // remember remote repository RemoteRepository repo = e.getConfigurable().getSource(); final String source = repo.getName(); addingConfigurablesFirstTime.remove(source); configurablesFetching.remove(source); // update UI // remove loading label remoteInfoLabelListModels.get(source).removeAllElements(); remoteTaskPanes.get(source).add(remoteConfigLists.get(source)); if (!remoteConfigListModels.containsKey(source)) { remoteConfigListModels.put(source, new DefaultListModel<Configurable>()); } int lastSelectedIndex = 0; for (Configurable config : getRemoteConfigurables(source)) { index = getRemoteConfigurables(source).indexOf(config); remoteConfigListModels.get(source).add(index, config); if (lastSelected != null) { if (config.getId() == lastSelected.getId()) { lastSelectedIndex = index; } } } if (!isAddingDialogOpened) { unselectAllOtherLists(repo); } if (getRemoteConfigurables(source).size() > 0) { if (!isAddingDialogOpened) { remoteConfigLists.get(source).setSelectedIndex(lastSelectedIndex); } } else { // if there are no connections available remoteInfoLabelListModels.get(source).removeAllElements(); remoteInfoLabelListModels.get(source) .addElement(ConfigurableInfoLabelType.NO_CONNECTIONS.toString()); remoteTaskPanes.get(source).repaint(); updateParameterPanel(null); } } } break; default: throw new IllegalStateException("event not handled!" + e.getEventType()); } Configurable configurable = getSelectedValue(); updateParameterPanel(configurable); } }; /** glass pane showing a saving icon and label */ private TransparentGlassPanePanel savingGlassPane; /** glass pane showing a gray transparent background */ private TransparentGlassPanePanel simpleGlassPane; /** layer above the {@link #parameterPanel} */ private JLayer<JPanel> parameterLayer; /** update queue for progress threads */ private final UpdateQueue updateQueue = new UpdateQueue("storeConfigurables"); /** drop down button to refresh the configurables */ private RefreshConfigurablesDropDownButton refreshButton; /** login button if the user of a remote repository is not admin and has no connections */ private LoginAsAdminDropDownButton smallLoginButton; /** layer on top of the outer panel */ private JLayer<JPanel> outerLayer; /** button panel to create */ private JPanel buttonPanel; /** action that is executed, when a user clicks cancel */ private Action cancelAction; /** configurable that was selected before a refresh */ private Configurable lastSelected; public ConfigurableDialog() { this(RapidMinerGUI.getMainFrame().getProcess()); } /** * @param openProcess * the currently opened process */ public ConfigurableDialog(Process openProcess) { super(ApplicationFrame.getApplicationFrame(), "configurable_dialog", ModalityType.MODELESS, new Object[] {}); Repository processLoc = null; try { processLoc = openProcess == null || openProcess.getRepositoryLocation() == null ? null : openProcess.getRepositoryLocation().getRepository(); if (processLoc instanceof RemoteRepository) { processLocation = (RemoteRepository) processLoc; } else { processLocation = null; } } catch (RepositoryException e) { // failure -> keep null and open local taskpane } // setup remote maps remoteInfoLabelLists = new HashMap<String, JList<String>>(); remoteConfigLists = new HashMap<String, JList<Configurable>>(); remoteControllers = new HashMap<String, ConfigurableController>(); remoteListener = new HashMap<String, ConfigurableModelEventListener>(); // setup source info label list model localInfoLabelListModel = new DefaultListModel<String>(); remoteInfoLabelListModels = new HashMap<String, DefaultListModel<String>>(); // setup configurable list model localConfigListModel = new DefaultListModel<Configurable>(); remoteConfigListModels = new HashMap<String, DefaultListModel<Configurable>>(); localListener = getConfigurableModelEventListener(); // setup model for this view ConfigurableModel localModel = new ConfigurableModel(null); localModel.registerEventListener(localListener); // setup controller for this view localController = new ConfigurableController(this, localModel); // fill list model with existing Configurables for (Configurable config : ConfigurationManager.getInstance().getAllConfigurables()) { // find the correct list if (config.getSource() == null) { localConfigListModel.addElement(config); } else { final String source = config.getSource().getName(); if (!remoteConfigListModels.containsKey(source)) { remoteConfigListModels.put(source, new DefaultListModel<Configurable>()); } if (!remoteInfoLabelListModels.containsKey(source)) { remoteInfoLabelListModels.put(source, new DefaultListModel<String>()); } if (!remoteListener.containsKey(source)) { remoteListener.put(source, getConfigurableModelEventListener()); // setup model final ConfigurableModel remoteModel = new ConfigurableModel(config.getSource()); remoteModel.registerEventListener(remoteListener.get(source)); if (config.getSource().isConnected()) { ProgressThread pt = new ProgressThread("check_server_version") { @Override public void run() { try { remoteModel.checkVersion(); if (!remoteModel.wasVersionCheckDone()) { collapseRemoteTaskPane(source); try { remoteModel.resetConfigurables(); remoteModel.resetConnection(); } catch (RepositoryException e1) { // connection could not be established } } } catch (WebServiceException e) { collapseRemoteTaskPane(source); try { remoteModel.resetConfigurables(); remoteModel.resetConnection(); } catch (RepositoryException e1) { // connection could not be established } } } }; pt.start(); } // setup controller remoteControllers.put(source, new ConfigurableController(this, remoteModel)); } remoteConfigListModels.get(source).addElement(config); } } List<RemoteRepository> remotes = RepositoryManager.getInstance(null).getRemoteRepositories(); for (final RemoteRepository repository : remotes) { if (!remoteConfigListModels.containsKey(repository.getName())) { remoteConfigListModels.put(repository.getName(), new DefaultListModel<Configurable>()); } if (!remoteInfoLabelListModels.containsKey(repository.getName())) { remoteInfoLabelListModels.put(repository.getName(), new DefaultListModel<String>()); } if (!remoteListener.containsKey(repository.getName())) { remoteListener.put(repository.getName(), getConfigurableModelEventListener()); // setup model final ConfigurableModel remoteModel = new ConfigurableModel(repository); remoteModel.registerEventListener(remoteListener.get(repository.getName())); if (repository.isConnected()) { ProgressThread pt = new ProgressThread("check_server_version") { @Override public void run() { try { remoteModel.checkVersion(); if (!remoteModel.wasVersionCheckDone()) { collapseRemoteTaskPane(repository.getName()); try { remoteModel.resetConfigurables(); remoteModel.resetConnection(); } catch (RepositoryException e1) { // connection could not be established } } } catch (WebServiceException e) { collapseRemoteTaskPane(repository.getName()); try { remoteModel.resetConfigurables(); remoteModel.resetConnection(); } catch (RepositoryException e1) { // connection could not be established } } } }; pt.start(); } // setup controller remoteControllers.put(repository.getName(), new ConfigurableController(this, remoteModel)); } } initGUI(); localConfigList.addListSelectionListener(createListSelectionListener(localConfigList)); for (JList<Configurable> remoteList : remoteConfigLists.values()) { remoteList.addListSelectionListener(createListSelectionListener(remoteList)); } updateQueue.start(); } private ListSelectionListener createListSelectionListener(final JList<Configurable> list) { return new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent e) { if (e.getValueIsAdjusting()) { return; } Configurable configurable = list.getSelectedValue(); updateParameterPanel(configurable); previousConfigurable = configurable; if (e.getSource() == list && configurable != null) { unselectAllOtherLists(configurable.getSource()); } updateButtonState(true); } }; } /** * Initializes the GUI. */ private void initGUI() { realOuterPanel = new JPanel(new BorderLayout()); outerLayer = new JLayer<JPanel>(realOuterPanel); savingGlassPane = new TransparentGlassPanePanel(WAITING_ICON, I18N.getGUILabel("configurable_dialog.saving_configurables"), getBackground(), 0.5f); outerLayer.setGlassPane(savingGlassPane); savingGlassPane.setVisible(false); JPanel pagePanel = new JPanel(new BorderLayout()); // list of configurables JPanel configPanel = createConfigPanel(); // force size so it does not resize itself depending on entered values configPanel.setMinimumSize(CONFIG_LIST_SIZE); configPanel.setMaximumSize(CONFIG_LIST_SIZE); configPanel.setPreferredSize(CONFIG_LIST_SIZE); buttonPanel = createConfigurableButtonPanel(); // create middle spacer JLabel spacer = new JLabel(); spacer.setMinimumSize(DIMENSION_SPACER_MIDDLE); spacer.setMaximumSize(DIMENSION_SPACER_MIDDLE); spacer.setPreferredSize(DIMENSION_SPACER_MIDDLE); // add both to an outer panel for layout reasons JPanel outerConfigPanel = new JPanel(new BorderLayout()); outerConfigPanel.setBorder(BorderFactory.createMatteBorder(0, 1, 1, 1, Color.LIGHT_GRAY)); outerConfigPanel.add(configPanel, BorderLayout.CENTER); outerConfigPanel.add(buttonPanel, BorderLayout.SOUTH); // another panel for layouting JPanel outermostConfigPanel = new JPanel(new BorderLayout()); outermostConfigPanel.add(outerConfigPanel, BorderLayout.CENTER); outermostConfigPanel.add(spacer, BorderLayout.EAST); // glass pane showed if the user is not able to edit connections due to an old version of // the server simpleGlassPane = new TransparentGlassPanePanel(null, null, getBackground(), 0.5f); // panel displaying the selected configurable JPanel paramPanel = createParameterPanel(); GridBagConstraints c = new GridBagConstraints(); c.fill = GridBagConstraints.BOTH; c.weightx = 1; c.weighty = 0.3; c.gridwidth = GridBagConstraints.REMAINDER; // add panels to page panel pagePanel.add(outermostConfigPanel, BorderLayout.WEST); pagePanel.add(paramPanel, BorderLayout.CENTER); // add page and button panel to outer panel realOuterPanel.add(pagePanel, BorderLayout.CENTER); layoutDefault(outerLayer, makeSaveButton(), makeCancel()); setDefaultSize(ButtonDialog.HUGE); setLocationRelativeTo(ApplicationFrame.getApplicationFrame()); setModal(true); setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { cancelButton.doClick(); } }); updateButtonState(true); } /** * Updates the parameter panel for the selected {@link Configurable}. */ private void updateParameterPanel(Configurable config) { parameterPanel.removeAll(); // save previously edited parameters if (configParamPanel != null && previousConfigurable != null) { if (previousConfigurable.getSource() == null) { localController.saveConfigurable(previousConfigurable, configParamPanel.getParameters()); } else { remoteControllers.get(previousConfigurable.getSource().getName()).saveConfigurable(previousConfigurable, configParamPanel.getParameters()); } } if (config != null) { try { // stripped text depending on the size of the panel String text = SwingTools.getStrippedJComponentText(outerPanel, config.getName(), outerPanel.getWidth() - 100, 0); nameLabel.setText("<html><b>" + text + "</b></html>"); // Get parameters based on Configurator implementation Parameters parameters = ConfigurationManager.getInstance().getAbstractConfigurator(config.getTypeId()) .getParameterHandler(config).getParameters(); // fill in real values of configurable for (String key : config.getParameters().keySet()) { parameters.setParameter(key, config.getParameters().get(key)); } // init param panel with real values configParamPanel = new ConfiguratorParameterPanel(this, parameters); parameterLayer = new JLayer<JPanel>(configParamPanel); parameterLayer.setGlassPane(simpleGlassPane); simpleGlassPane.setVisible(false); // add it to wrapper panel parameterPanel.add(parameterLayer, BorderLayout.CENTER); boolean editingAllowed = true; boolean editingPossible = true; if (config.getSource() != null) { if (config.getSource().isConnected()) { if (!remoteControllers.get(config.getSource().getName()).getModel().hasAdminRights()) { editingAllowed = false; } // only interesting if we want to edit remote connections editingPossible = remoteControllers.get(config.getSource().getName()).getModel().isEditingPossible(); } } if (!editingPossible) { SwingTools.setEnabledRecursive(configParamPanel, false); simpleGlassPane.setVisible(true); } else { if (!editingAllowed) { SwingTools.setEnabledRecursive(configParamPanel, false); simpleGlassPane.setVisible(true); renameButton.setVisible(false); removeButton.setVisible(false); actionPanel.setVisible(false); } else { if (!configParamPanel.isEnabled()) { SwingTools.setEnabledRecursive(configParamPanel, true); } if (simpleGlassPane.isVisible()) { simpleGlassPane.setVisible(false); } // make editing components visible renameButton.setVisible(true); removeButton.setVisible(true); actionPanel.setVisible(true); } } } catch (Exception e) { LogService.getRoot().log(Level.WARNING, "com.rapidminer.tools.config.gui.ConfigurableDialog.error_setting_parameters", e); // display error in GUI parameterPanel.removeAll(); JLabel errorLabel = new JLabel( I18N.getGUIMessage(I18N .getGUIMessage("gui.dialog.configurable_dialog.error.display_stored_configurable.label")), FAILURE_ICON, SwingConstants.LEADING); errorLabel.setHorizontalAlignment(SwingConstants.CENTER); parameterPanel.add(errorLabel, BorderLayout.CENTER); } } updateButtonState(true); parameterPanel.revalidate(); parameterPanel.repaint(); } /** * Checks if there is at least one user without admin rights * * @return number of users without admin rights */ private int getNumberOfUsersWithoutAdminRights() { int users = 0; for (ConfigurableController controller : remoteControllers.values()) { ConfigurableModel model = controller.getModel(); boolean notUpdating = addingConfigurablesFirstTime.get(model.getSource().getName()) == null || !addingConfigurablesFirstTime.get(model.getSource().getName()).booleanValue(); boolean notFetching = configurablesFetching.get(model.getSource().getName()) == null || !configurablesFetching.get(model.getSource().getName()).booleanValue(); if (model.getSource().isConnected()) { if (notUpdating && notFetching) { if (!model.hasAdminRights()) { users++; } } } } return users; } /** * Creates the panel which display the available {@link Configurable}s and buttons to add/remove * new ones. */ private JPanel createConfigPanel() { JPanel configPanel = new JPanel(); configPanel.setLayout(new GridBagLayout()); configContainer = new JXTaskPaneContainer(); configContainer.setBackgroundPainter(new MattePainter(Color.white)); /* background color */ UIManager.put("TaskPane.background", LIGHTER_GRAY); /* title hover color */ UIManager.put("TaskPane.titleOver", SwingTools.RAPIDMINER_ORANGE); UIManager.put("TaskPane.specialTitleOver", SwingTools.RAPIDMINER_ORANGE); /* border color */ UIManager.put("TaskPane.borderColor", this.getBackground()); /* foreground */ UIManager.put("TaskPane.foreground", Color.black); UIManager.put("TaskPane.titleForeground", Color.black); UIManager.put("TaskPane.specialTitleForeground", Color.black); /* title background */ UIManager.put("TaskPane.specialTitleBackground", this.getBackground()); UIManager.put("TaskPane.titleBackgroundGradientStart", this.getBackground()); UIManager.put("TaskPane.titleBackgroundGradientEnd", this.getBackground()); // add local task pane localTaskPane = new JXTaskPane(); localTaskPane.setName("localGroup"); localTaskPane.setTitle("Local"); localTaskPane.setAnimated(false); localInfoLabelList = createNewInfoLabelJList(null); localTaskPane.add(localInfoLabelList); localConfigList = createNewConfigurableJList(null); localTaskPane.add(localConfigList); if (processLocation == null) { localTaskPane.setCollapsed(false); } configContainer.add(localTaskPane); // add remote task panes remoteTaskPanes = new HashMap<>(); int i = 1; for (final String source : remoteConfigListModels.keySet()) { final JXTaskPane remoteTaskPane = new JXTaskPane(); remoteTaskPane.setName("remoteGroup" + i); remoteInfoLabelLists.put(source, createNewInfoLabelJList(source)); remoteTaskPane.add(remoteInfoLabelLists.get(source)); remoteConfigLists.put(source, createNewConfigurableJList(source)); remoteTaskPane.add(remoteConfigLists.get(source)); remoteTaskPane.setTitle(source); remoteTaskPane.setAnimated(false); remoteTaskPane.addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { if (remoteConfigListModels.get(source).isEmpty()) { boolean notFetching = configurablesFetching.get(source) == null || !configurablesFetching.get(source).booleanValue(); if (notFetching) { ProgressThread pt = new ProgressThread("load_configurables") { @Override public void run() { configurablesFetching.put(source, true); getProgressListener().setTotal(100); getProgressListener().setCompleted(10); List<RemoteRepository> remotes = RepositoryManager.getInstance(null) .getRemoteRepositories(); for (RemoteRepository repository : remotes) { if (repository.getName().equals(source)) { // if the remote task pane was opened if (!remoteTaskPane.isCollapsed()) { // if the repository is not yet connected if (!repository.isConnected()) { addingConfigurablesFirstTime.put(source, true); remoteInfoLabelListModels.get(source).removeAllElements(); remoteInfoLabelListModels.get(source) .addElement(ConfigurableInfoLabelType.LOADING.toString()); remoteTaskPane.repaint(); // try to connect try { repository.setPasswortInputCanceled(false); getProgressListener().setCompleted(30); if (!repository.isReachable()) { throw new RepositoryException(); } getProgressListener().setCompleted(80); } catch (RepositoryException e1) { // timeout or connection failed remoteInfoLabelListModels.get(source).removeAllElements(); remoteInfoLabelListModels.get(source) .addElement(ConfigurableInfoLabelType.FAILED.toString()); addingConfigurablesFirstTime.remove(source); configurablesFetching.remove(source); } remoteControllers.get(source).getModel().isEditingPossible(); // update UI remoteTaskPane.repaint(); } else { // if there are no connections available if (remoteControllers.get(source).getModel().getConfigurables() .isEmpty()) { remoteInfoLabelListModels.get(source).removeAllElements(); remoteInfoLabelListModels.get(source).addElement( ConfigurableInfoLabelType.NO_CONNECTIONS.toString()); remoteTaskPane.repaint(); } } } break; } } getProgressListener().setCompleted(100); getProgressListener().complete(); configurablesFetching.remove(source); remoteTaskPane.repaint(); } }; pt.start(); } } } }); if (processLocation == null) { remoteTaskPane.setCollapsed(true); } else { if (source.equals(processLocation.getName())) { remoteTaskPane.setCollapsed(false); localTaskPane.setCollapsed(true); } else { remoteTaskPane.setCollapsed(true); } } configContainer.add(remoteTaskPane); remoteTaskPanes.put(source, remoteTaskPane); i++; } configContainer.add(Box.createVerticalStrut(5)); JScrollPane configScroll = new ExtendedJScrollPane(configContainer); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 0; gbc.weightx = 1.0; gbc.weighty = 1.0; gbc.fill = GridBagConstraints.BOTH; configPanel.add(configScroll, gbc); return configPanel; } /** * Creates a new JList for a given source of a configurable * * @param source * can be null for local configurables, otherwise name of the source * @return the created JList */ private JList<Configurable> createNewConfigurableJList(String source) { final JList<Configurable> createdConfigList = new JList<>(); createdConfigList.setModel(source == null ? localConfigListModel : remoteConfigListModels.get(source)); createdConfigList.setCellRenderer(new ConfigurableRenderer()); createdConfigList.setFixedCellHeight(40); createdConfigList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); createdConfigList.setBackground(LIGHTER_GRAY); return createdConfigList; } /** * Creates a new JList for info labels of a source * * @param source * can be null for local source, otherwise name of the source * @return the created JList */ private JList<String> createNewInfoLabelJList(String source) { final JList<String> createdInfoLabelList = new JList<>(); createdInfoLabelList.setModel(source == null ? localInfoLabelListModel : remoteInfoLabelListModels.get(source)); createdInfoLabelList.setCellRenderer(new ConfigurableInfoLabelRenderer()); createdInfoLabelList.setFixedCellHeight(20); createdInfoLabelList.setBackground(LIGHTER_GRAY); return createdInfoLabelList; } /** * Unselects all other lists without triggering events * * @param source * can be null for the local connection list, otherwise remote connection source */ private void unselectAllOtherLists(RemoteRepository source) { // if a local connection is selected, clear the selection of all remote connection lists if (source == null) { for (JList<Configurable> list : remoteConfigLists.values()) { clearSelection(list); } } else { // clear the selection of the local connection list clearSelection(localConfigList); // clear the selection of all other remote connection lists for (String key : remoteConfigLists.keySet()) { if (!source.getName().equals(key)) { JList<Configurable> list = remoteConfigLists.get(key); clearSelection(list); } } } } /** * Clears the selection of a {@link JList} without triggering of {@link ListSelectionEvent}s * * @param list * @param key */ private void clearSelection(JList<Configurable> list) { ListSelectionListener[] oldListSelectionListeners = list.getListSelectionListeners(); for (ListSelectionListener exListener : oldListSelectionListeners) { list.removeListSelectionListener(exListener); } list.clearSelection(); list.setFocusable(false); list.setFocusable(true); for (ListSelectionListener exListener : oldListSelectionListeners) { list.addListSelectionListener(exListener); } } /** * Creates the panel which contains the parameters as well as the {@link ConfigurableAction} s. * * @return */ private JPanel createParameterPanel() { outerPanel = new JPanel(new BorderLayout()); namePanel = new JPanel(new GridBagLayout()); namePanel.setBackground(NAME_PANEL_GRAY); namePanel.setMinimumSize(new Dimension(namePanel.getMinimumSize().width, 50)); namePanel.setPreferredSize(new Dimension(namePanel.getPreferredSize().width, 50)); namePanel.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Color.LIGHT_GRAY)); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 0; gbc.insets = new Insets(5, 10, 5, 5); gbc.weighty = 1.0; gbc.fill = GridBagConstraints.VERTICAL; nameLabel = new JLabel(); nameLabel.setToolTipText(I18N.getGUILabel("configurable_dialog.name_config.tip")); nameLabel.setVisible(true); gbc.anchor = GridBagConstraints.WEST; namePanel.add(nameLabel, gbc); JPanel buttonPanel = new JPanel(); buttonPanel.setBackground(NAME_PANEL_GRAY); renameButton = new JButton(new ResourceActionAdapter(true, "configurable_dialog.rename_config") { private static final long serialVersionUID = 1L; @Override public void actionPerformed(ActionEvent e) { boolean done = false; final Configurable config = getSelectedValue(); if (config == null) { return; } boolean localConfigurable = config.getSource() == null; boolean editingPossible = localConfigurable; boolean editingAllowed = localConfigurable; if (!localConfigurable) { ConfigurableController remoteController = remoteControllers.get(config.getSource().getName()); if (remoteController.getModel().isEditingPossible()) { editingPossible = true; } if (remoteController.getModel().hasAdminRights()) { editingAllowed = true; } } if (editingPossible && editingAllowed) { // show input while user enters invalid values, if user clicks cancel or // finished correctly, abort loop do { String name = SwingTools.showInputDialog(ConfigurableDialog.this, "configurable_dialog.rename", config.getName()); if (name == null) { // user cancelled dialog break; } if (name.equals(config.getName())) { // user did not change the name break; } if ("".equals(name.trim())) { SwingTools.showVerySimpleErrorMessage(ConfigurableDialog.this, "configurable_creation_dialog.invalid_name"); continue; } ConfigurableController controller = config.getSource() == null ? localController : remoteControllers.get(config.getSource().getName()); boolean isUnique = controller.isNameUniqueForType(config.getTypeId(), name); if (!isUnique) { SwingTools.showVerySimpleErrorMessage(ConfigurableDialog.this, "configurable_creation_dialog.invalid_duplicate_name"); continue; } else { controller.renameConfigurable(config, name); updateParameterPanel(config); done = true; localConfigList.repaint(); for (JList<Configurable> remoteList : remoteConfigLists.values()) { remoteList.repaint(); } } } while (!done); } } }); // listen to F2 types and do the rename action KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0); buttonPanel.registerKeyboardAction(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { renameButton.doClick(); } }, keyStroke, JComponent.WHEN_IN_FOCUSED_WINDOW); renameButton.setBorderPainted(false); renameButton.setContentAreaFilled(false); renameButton.setRolloverEnabled(false); renameButton.setVisible(false); renameButton.addMouseListener(new MouseAdapter() { @Override public void mouseExited(MouseEvent e) { renameButton.setBorderPainted(false); } @Override public void mouseEntered(MouseEvent e) { renameButton.setBorderPainted(true); } }); gbc.gridx += 1; gbc.anchor = GridBagConstraints.EAST; // gbc.weightx = 0.95; buttonPanel.add(renameButton); removeButton = new JButton(new ResourceActionAdapter(true, "configurable_dialog.remove_config") { private static final long serialVersionUID = 1L; @Override public void actionPerformed(ActionEvent e) { Configurable selectedValue = getSelectedValue(); if (selectedValue == null) { return; } if (selectedValue.getSource() == null) { localController.removeConfigurable(localConfigList.getSelectedValue()); } else { ConfigurableController remoteController = remoteControllers.get(selectedValue.getSource().getName()); if (remoteController.getModel().isEditingPossible()) { if (remoteController.getModel().hasAdminRights()) { remoteController.removeConfigurable( remoteConfigLists.get(selectedValue.getSource().getName()).getSelectedValue()); } } } } }); // listen to DELETE types and do the remove action KeyStroke keyStrokeRemove = KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0); buttonPanel.registerKeyboardAction(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { removeButton.doClick(); } }, keyStrokeRemove, JComponent.WHEN_IN_FOCUSED_WINDOW); removeButton.setBorderPainted(false); removeButton.setContentAreaFilled(false); removeButton.setRolloverEnabled(false); removeButton.setVisible(false); removeButton.addMouseListener(new MouseAdapter() { @Override public void mouseExited(MouseEvent e) { removeButton.setBorderPainted(false); } @Override public void mouseEntered(MouseEvent e) { removeButton.setBorderPainted(true); } }); gbc.gridx += 1; gbc.weightx = 0.95; buttonPanel.add(removeButton); namePanel.add(buttonPanel, gbc); // setup parameter panel parameterPanel = new JPanel(new BorderLayout()); actionPanel.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, Color.LIGHT_GRAY)); gbc.gridx = 0; gbc.weightx = 0; gbc.anchor = GridBagConstraints.WEST; gbc.fill = GridBagConstraints.NONE; configActionsButton = new JButton(new ResourceActionAdapter(false, "configurable_dialog.show_actions") { private static final long serialVersionUID = 1L; @Override public void actionPerformed(ActionEvent e) { // skip if we started this without configurable if (getSelectedValue() == null) { return; } Configurable configValue = previousConfigurable; if (AbstractConfigurable.class.isAssignableFrom(configValue.getClass())) { AbstractConfigurable configurable = (AbstractConfigurable) configValue; if (configurable.getActions() != null && configurable.getActions().size() > 0) { JPopupMenu actionMenu = new ScrollableJPopupMenu(); // create one menu item for each action defined by the configurable for (final ConfigurableAction action : configurable.getActions()) { JMenuItem actionItem = new JMenuItem(); actionItem.setIcon(SwingTools.createIcon("24/" + action.getIconName())); actionItem.setText(action.getName()); actionItem.setToolTipText(action.getTooltip()); actionItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // reset last results testLabel.setIcon(null); // store fresh changes previousConfigurable = getSelectedValue(); if (previousConfigurable.getSource() == null) { localController.saveConfigurable(previousConfigurable, configParamPanel.getParameters()); localController.executeConfigurableAction(action); } else { remoteControllers.get(previousConfigurable.getSource().getName()) .saveConfigurable(previousConfigurable, configParamPanel.getParameters()); remoteControllers.get(previousConfigurable.getSource().getName()) .executeConfigurableAction(action); } } }); actionMenu.add(actionItem); } actionMenu.show(configActionsButton, 0, (int) configActionsButton.getSize().getHeight()); } } } }); configActionsButton.setEnabled(false); actionPanel.add(configActionsButton, gbc); gbc.gridx += 1; gbc.weightx = 0.0; testButton = new JButton(new ResourceActionAdapter(false, "configurable_dialog.test_configurable") { private static final long serialVersionUID = 1L; @Override public void actionPerformed(ActionEvent e) { // skip if we started this without configurable if (getSelectedValue() == null) { return; } // prevent multiple tests from running testButton.setEnabled(false); // reset last results testLabel.setIcon(null); // store fresh changes previousConfigurable = getSelectedValue(); if (previousConfigurable.getSource() == null) { localController.saveConfigurable(previousConfigurable, configParamPanel.getParameters()); } else { remoteControllers.get(previousConfigurable.getSource().getName()).saveConfigurable(previousConfigurable, configParamPanel.getParameters()); } Configurable configValue = previousConfigurable; if (AbstractConfigurable.class.isAssignableFrom(configValue.getClass())) { AbstractConfigurable configurable = (AbstractConfigurable) configValue; if (configurable.getTestAction() != null) { if (previousConfigurable.getSource() == null) { localController.executeConfigurableAction(configurable.getTestAction()); } else { remoteControllers.get(previousConfigurable.getSource().getName()) .executeConfigurableAction(configurable.getTestAction()); } } } else { testButton.setEnabled(true); } } }); testButton.setEnabled(false); actionPanel.add(testButton, gbc); gbc.gridx += 1; testLabel = new JLabel(); actionPanel.add(testLabel, gbc); // create middle spacer gbc.gridx += 1; gbc.weightx = 1.0; gbc.fill = GridBagConstraints.BOTH; actionPanel.add(new JLabel(), gbc); gbc.gridx += 1; gbc.weightx = 0; gbc.weighty = 0; gbc.anchor = GridBagConstraints.EAST; gbc.fill = GridBagConstraints.NONE; userAccessLabel = new JLabel("<html><font color=\"red\"><b>0</b> " + userAccessText + "</font></html>"); userAccessLabel.setVisible(false); actionPanel.add(userAccessLabel, gbc); userAccessButton = new JButton(new ResourceAction(false, "configurable_dialog.source_access") { private static final long serialVersionUID = 1L; @Override public void actionPerformed(ActionEvent e) { Configurable configurable = getSelectedValue(); ConfigurableUserAccessDialog accessDialog = new ConfigurableUserAccessDialog(ConfigurableDialog.this, configurable); accessDialog.setVisible(true); ConfigurationManager.getInstance().setPermittedGroupsForConfigurable(configurable, accessDialog.getPermittedUserGroups()); updateSourceAccessLabel(true); } }); userAccessButton.setVisible(false); gbc.gridx += 1; actionPanel.add(userAccessButton, gbc); final ExtendedJScrollPane paramScrollPane = new ExtendedJScrollPane(parameterPanel); paramScrollPane.setBorder(null); JLabel spacer = new JLabel(); spacer.setMinimumSize(DIMENSION_SPACER_PARAMS); spacer.setMaximumSize(DIMENSION_SPACER_PARAMS); spacer.setPreferredSize(DIMENSION_SPACER_PARAMS); // construct outer panel outerPanel.add(spacer, BorderLayout.WEST); outerPanel.add(namePanel, BorderLayout.NORTH); outerPanel.add(paramScrollPane, BorderLayout.CENTER); outerPanel.add(actionPanel, BorderLayout.SOUTH); outerPanel.setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, Color.LIGHT_GRAY)); return outerPanel; } /** * Creates the button panel containing the buttons for the {@link Configurable} list. * * @param buttonPanel */ private JPanel createConfigurableButtonPanel() { JPanel buttonPanel = new JPanel(); buttonPanel.setLayout(new GridBagLayout()); GridBagConstraints buttonGBC = new GridBagConstraints(); final JButton addButton = new JButton(new ResourceActionAdapter(false, "configurable_dialog.add_config") { private static final long serialVersionUID = 1L; @Override public void actionPerformed(ActionEvent e) { Configurable selected = getSelectedValue(); RemoteRepository source = selected == null ? null : selected.getSource(); ConfigurableCreationDialog dialog = new ConfigurableCreationDialog(ConfigurableDialog.this, localController, remoteControllers, source, preferredTypeId); isAddingDialogOpened = true; dialog.setVisible(true); } }); buttonGBC.gridx = 0; buttonGBC.fill = GridBagConstraints.HORIZONTAL; buttonGBC.weightx = 0.5f; buttonGBC.insets = new Insets(5, 5, 5, 0); buttonPanel.add(addButton, buttonGBC); JPanel panelRefreshButton = new JPanel(new GridLayout(1, 2, 5, 5)); refreshButton = new RefreshConfigurablesDropDownButton(remoteControllers); smallLoginButton = new LoginAsAdminDropDownButton(this, remoteControllers); panelRefreshButton.add(refreshButton); panelRefreshButton.add(smallLoginButton); buttonGBC.insets = new Insets(0, 5, 0, 5); buttonGBC.gridx += 1; buttonPanel.add(panelRefreshButton, buttonGBC); buttonPanel.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, Color.LIGHT_GRAY)); return buttonPanel; } /** * Creates the Save button which saves all the changes the user has created. * * @return */ private AbstractButton makeSaveButton() { Action okAction = new ResourceAction("configurable_dialog.save_all") { private static final long serialVersionUID = 1L; @Override public void actionPerformed(ActionEvent e) { // now we need to save the changes the user made // in a separate thread localController.getModel().removeEventListener(localListener); for (String remote : remoteListener.keySet()) { remoteControllers.get(remote).getModel().removeEventListener(remoteListener.get(remote)); } // show the glass pane okButton.setEnabled(false); cancelButton.setEnabled(false); savingGlassPane.setVisible(true); SwingTools.setEnabledRecursive(realOuterPanel, false); ProgressThread pt = new ProgressThread("store_configurables") { @Override public void run() { getProgressListener().setTotal(100); getProgressListener().setCompleted(10); // save edited parameters of current configurable Configurable config = getSelectedValue(); if (configParamPanel != null && config != null) { if (config.getSource() == null) { localController.saveConfigurable(config, configParamPanel.getParameters()); } else { remoteControllers.get(config.getSource().getName()).saveConfigurable(config, configParamPanel.getParameters()); } } // check if current configurable is in valid state, i.e. all required // parameters // are // set. If not, switch to broken config and display problem to user for (final Configurable configurable : localController.getModel().getConfigurables()) { final ActionResult result = localController.checkConfigurableValidState(configurable); if (result.getResult().equals(Result.FAILURE)) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { okButton.setEnabled(true); cancelButton.setEnabled(true); savingGlassPane.setVisible(false); SwingTools.setEnabledRecursive(realOuterPanel, true); // switch to the broken one localConfigList.setSelectedValue(configurable, true); displayResult(result); } }); return; } } for (final String source : remoteControllers.keySet()) { if (remoteControllers.get(source).getModel().getSource().isConnected()) { if (remoteControllers.get(source).getModel().isEditingPossible()) { for (final Configurable configurable : remoteControllers.get(source).getModel() .getConfigurables()) { final ActionResult result = remoteControllers.get(source) .checkConfigurableValidState(configurable); if (result.getResult().equals(Result.FAILURE)) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { okButton.setEnabled(true); cancelButton.setEnabled(true); savingGlassPane.setVisible(false); SwingTools.setEnabledRecursive(realOuterPanel, true); // switch to the broken one remoteConfigLists.get(source).setSelectedValue(configurable, true); displayResult(result); } }); return; } } } } } localController.save(); for (Entry<String, ConfigurableController> entry : remoteControllers.entrySet()) { entry.getValue().save(); entry.getValue().getModel().resetCredentials(); } getProgressListener().setCompleted(100); getProgressListener().complete(); // run this in a GUI thread SwingUtilities.invokeLater(new Runnable() { @Override public void run() { savingGlassPane.setVisible(false); setConfirmed(true); ConfigurableDialog.super.dispose(); } }); } }; updateQueue.executeBackgroundJob(pt); } }; okButton = new JButton(okAction); return okButton; } /** * Creates the Cancel button which discards all the changes the user made. * * @return */ private AbstractButton makeCancel() { cancelAction = new ResourceAction("cancel") { private static final long serialVersionUID = 1L; @Override public void actionPerformed(ActionEvent e) { // show the glass pane okButton.setEnabled(false); cancelButton.setEnabled(false); savingGlassPane.setText(""); savingGlassPane.setVisible(true); SwingTools.setEnabledRecursive(realOuterPanel, false); // if dialog was closed via 'Cancel', revert any changes localController.revertChanges(); for (ConfigurableController remoteController : remoteControllers.values()) { remoteController.revertChanges(); } localController.getModel().removeEventListener(localListener); for (String remote : remoteListener.keySet()) { remoteControllers.get(remote).getModel().removeEventListener(remoteListener.get(remote)); } new ProgressThread("refresh_configurables") { @Override public void run() { for (String remote : remoteListener.keySet()) { remoteControllers.get(remote).getModel().resetCredentials(); } SwingUtilities.invokeLater(new Runnable() { @Override public void run() { ConfigurableDialog.super.dispose(); } }); } }.start(); } }; cancelButton = new JButton(cancelAction); // make ESC close dialog getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false), "CANCEL"); getRootPane().getActionMap().put("CANCEL", cancelAction); return cancelButton; } /** * Updates the state of the buttons and the test result label depending on the currently * selected {@link Configurable}. * * @param resetMessage */ private void updateButtonState(boolean resetMessage) { Configurable configurable = getSelectedValue(); boolean editingPossible = true; boolean editingAllowed = true; if (configurable != null) { if (configurable.getSource() != null) { if (configurable.getSource().isConnected()) { if (!remoteControllers.get(configurable.getSource().getName()).getModel().hasAdminRights()) { editingAllowed = false; } // only interesting if we want to edit remote connections editingPossible = remoteControllers.get(configurable.getSource().getName()).getModel() .isEditingPossible(); } } } // show the actionPanel only if configurable != null and editing is allowed // show the name panel if a configurable is selected and show the rename and remove // button // if the editing is allowed namePanel.setVisible(configurable != null); renameButton.setVisible(configurable != null && editingAllowed && editingPossible); removeButton.setVisible(configurable != null && editingAllowed && editingPossible); actionPanel.setVisible(configurable != null); userAccessButton .setVisible(configurable != null && configurable.getSource() != null && editingAllowed && editingPossible); updateSourceAccessLabel(editingAllowed && editingPossible); if (resetMessage) { testLabel.setIcon(null); } if (configurable != null) { nameLabel.setIcon(SwingTools.createIcon("24/" + ConfigurationManager.getInstance().getAbstractConfigurator(configurable.getTypeId()).getIconName())); if (configurable != null && AbstractConfigurable.class.isAssignableFrom(configurable.getClass())) { AbstractConfigurable abstractConfig = (AbstractConfigurable) configurable; configActionsButton.setEnabled(abstractConfig.getActions() != null); testButton.setEnabled(abstractConfig.getTestAction() != null); } } updateRefreshButton(); updateSmallLoginButton(); } private void updateRefreshButton() { // check if the refresh button should be visible (if there are connected remote // repositories) int counter = 0; for (ConfigurableController controller : remoteControllers.values()) { if (controller.getModel().getSource().isConnected()) { counter++; } } if (counter > 0) { if (!refreshButton.isVisible()) { refreshButton.setVisible(true); } } else { if (refreshButton.isVisible()) { refreshButton.setVisible(false); } } } private void updateSmallLoginButton() { // check if the small login button should be visible (if there are connected remote // repositories) int counter = getNumberOfUsersWithoutAdminRights(); if (counter > 0) { if (!smallLoginButton.isVisible()) { smallLoginButton.setVisible(true); } } else { if (smallLoginButton.isVisible()) { smallLoginButton.setVisible(false); } } } /** * Updates the text of the {@link ConfigurableDialog#userAccessLabel} depending on the currently * selected {@link Configurable}. * */ private void updateSourceAccessLabel(boolean editingEnabled) { Configurable configurable = getSelectedValue(); if (configurable != null && configurable.getSource() != null && editingEnabled) { userAccessLabel.setVisible(true); int noOfAccessingUsers = ConfigurationManager.getInstance().getPermittedGroupsForConfigurable(configurable) .size(); if (noOfAccessingUsers == 0) { userAccessLabel.setText( "<html><font color=\"red\"><b>" + noOfAccessingUsers + "</b> " + userAccessText + "</font></html>"); } else if (noOfAccessingUsers == 1) { userAccessLabel.setText("<html><b>" + noOfAccessingUsers + "</b> " + singleUserAccessText + "</html>"); } else { userAccessLabel.setText("<html><b>" + noOfAccessingUsers + "</b> " + userAccessText + "</html>"); } } else { userAccessLabel.setVisible(false); } } /** * Displays the result of a test action or a configurator action. */ protected void displayResult(ActionResult result) { ImageIcon icon = null; if (Result.SUCCESS.equals(result.getResult())) { icon = SUCCESS_ICON; testLabel.setIcon(icon); // SwingTools.showMessageDialog(ConfigurableDialog.this, "configuration.test.success", // result.getMessage()); } else if (Result.FAILURE.equals(result.getResult())) { icon = FAILURE_ICON; testLabel.setIcon(icon); SwingTools.showVerySimpleErrorMessage(ConfigurableDialog.this, "configuration.test.fail", result.getMessage()); } testLabel.setToolTipText(result.getMessage()); updateButtonState(false); } /** * Displays that an action is currently running. */ protected void displayActionIsRunning() { testLabel.setIcon(WORKING_ICON); } /** * Displays an error dialog indicating that saving has failed. */ protected void displaySaveErrorDialog() { SwingTools.showVerySimpleErrorMessage(ConfigurableDialog.this, "configurable_dialog.save_configurable"); } /** * Displays an error dialog indicating that saving has failed due to the server which is not * up-to-date. */ protected void displaySaveUploadErrorDialogServerNotUpToDate(String serverName) { SwingTools.showVerySimpleErrorMessage(ConfigurableDialog.this, "configurable_controller_upload_error_server_not_up_to_date", serverName); } /** * Displays an error dialog indicating that saving for a specific typeId has failed. */ protected void displaySaveUploadErrorDialog(String typeId, String repositoryName, String repositoryURL) { SwingTools.showVerySimpleErrorMessage(ConfigurableDialog.this, "configurable_controller_upload_error_server", typeId, repositoryName, repositoryURL); } /** * Displays an error dialog indicating that the connection to the server has failed. */ protected void displayConnectionErrorDialog(String repositoryName, String repositoryURL) { SwingTools.showVerySimpleErrorMessage(ConfigurableDialog.this, "configurable_controller_connection_failed", repositoryName, repositoryURL); } /** * Collapses a remote task pane, if it exists */ protected void collapseRemoteTaskPane(String repositoryName) { if (remoteTaskPanes.containsKey(repositoryName)) { remoteTaskPanes.get(repositoryName).setCollapsed(true); } } /** * Tries to select the specified {@link Configurable} identified via its name and typeId. */ public void selectConfigurable(String configurableName, String typeId) { // set a preferred typeId for new configurables // dialog is started from the parameter panel of a specific operator which needs a // preferred // configuration type preferredTypeId = typeId; // go through all existing configurables in the models, try to find and select it boolean done = false; if (processLocation != null) { localTaskPane.setCollapsed(true); for (String source : remoteConfigListModels.keySet()) { if (processLocation.getName().equals(source)) { remoteTaskPanes.get(source).setCollapsed(false); // check if you find a configurable with the given name and preferred typeid for (int i = 0; i < remoteConfigListModels.get(source).size(); i++) { if (remoteConfigListModels.get(source).get(i).getName().equals(configurableName)) { if (remoteConfigListModels.get(source).get(i).getTypeId().equals(preferredTypeId)) { remoteConfigLists.get(source).setSelectedIndex(i); done = true; break; } } } // if this was not possible if (!done) { // check if you find any configurable with the preferred typeid for (int i = 0; i < remoteConfigListModels.get(source).size(); i++) { if (remoteConfigListModels.get(source).get(i).getTypeId().equals(preferredTypeId)) { remoteConfigLists.get(source).setSelectedIndex(i); done = true; break; } } // if this was also not possible if (!done) { // select the first element if there is one if (remoteControllers.get(source).getModel().getConfigurables().size() > 0) { remoteConfigLists.get(source).setSelectedIndex(0); } } } } else { remoteTaskPanes.get(source).setCollapsed(true); } } } else { localTaskPane.setCollapsed(false); for (int i = 0; i < localConfigListModel.size(); i++) { // check if you find a configurable with the given name and preferred typeid if (localConfigListModel.get(i).getName().equals(configurableName)) { if (localConfigListModel.get(i).getTypeId().equals(preferredTypeId)) { localConfigList.setSelectedIndex(i); done = true; break; } } } // if this was also not possible if (!done) { for (int i = 0; i < localConfigListModel.size(); i++) { // check if you find any configurable with the preferred typeid if (localConfigListModel.get(i).getTypeId().equals(preferredTypeId)) { localConfigList.setSelectedIndex(i); done = true; break; } } // if this was also not possible if (!done) { // select the first element if there is one if (localController.getModel().getConfigurables().size() > 0) { localConfigList.setSelectedIndex(0); } } } for (String source : remoteConfigListModels.keySet()) { remoteTaskPanes.get(source).setCollapsed(true); } } } private Configurable getSelectedValue() { if (!localConfigList.isSelectionEmpty()) { return localConfigList.getSelectedValue(); } else { for (JList<Configurable> list : remoteConfigLists.values()) { if (!list.isSelectionEmpty()) { return list.getSelectedValue(); } } } return null; } private ConfigurableModelEventListener getConfigurableModelEventListener() { return modelEventListener; } /** * @param source * the source of the remote repository * @return the list of configurables */ private List<Configurable> getRemoteConfigurables(final String source) { return remoteControllers.get(source).getModel().getConfigurables(); } /** * Reloads configurables for the given source and task pane. * * @param source * @param remoteTaskPane */ private void updateConfigurables(final String source, final JXTaskPane remoteTaskPane) { if (remoteConfigListModels.get(source).isEmpty()) { boolean notFetching = configurablesFetching.get(source) == null || !configurablesFetching.get(source).booleanValue(); if (notFetching) { ProgressThread pt = new ProgressThread("refresh_configurables") { @Override public void run() { configurablesFetching.put(source, true); getProgressListener().setTotal(100); getProgressListener().setCompleted(10); for (ConfigurableController controller : remoteControllers.values()) { RemoteRepository repository = controller.getModel().getSource(); if (repository.getName().equals(source)) { addingConfigurablesFirstTime.put(source, true); remoteInfoLabelListModels.get(source).removeAllElements(); remoteInfoLabelListModels.get(source) .addElement(ConfigurableInfoLabelType.LOADING.toString()); remoteTaskPane.repaint(); // try to connect try { repository.setPasswortInputCanceled(false); getProgressListener().setCompleted(30); remoteControllers.get(source).getModel().resetConnection(); getProgressListener().setCompleted(80); } catch (RepositoryException e1) { // timeout or connection failed remoteInfoLabelListModels.get(source).removeAllElements(); remoteInfoLabelListModels.get(source) .addElement(ConfigurableInfoLabelType.FAILED.toString()); addingConfigurablesFirstTime.remove(source); configurablesFetching.remove(source); } remoteControllers.get(source).getModel().isEditingPossible(); // update UI remoteTaskPane.repaint(); break; } } getProgressListener().setCompleted(100); getProgressListener().complete(); configurablesFetching.remove(source); remoteTaskPane.repaint(); } }; pt.start(); } } } /** * Refreshes {@link Configurable}s for the given source * * @param source * Name of the {@link RemoteRepository}, from where the {@link Configurable}s are * loaded */ public void refreshConfigurables(String source) { // reset the task panes, connections and reload them // make sure they are added together addingConfigurablesFirstTime.put(source, true); lastSelected = getSelectedValue(); remoteTaskPanes.get(source).setCollapsed(false); // reset the old configurables remoteControllers.get(source).getModel().resetConfigurables(); // reload the configurables (contains resetConnection) updateConfigurables(source, remoteTaskPanes.get(source)); } }